import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';

class SearchBoxWidget extends StatefulWidget {
  final ValueChanged<String?> onValueChanged;
  final ValueChanged<String?>? onLastValueChanged;
  final VoidCallback? onClear;
  final Widget? prefix;
  final String hintText;
  final double borderRadius;
  final double verticalMargin;
  final double contentVerticalPadding;
  final double horizontalMargin;
  final double leftPadding;
  final ValueChanged<String>? onSubmitted;
  final bool enabled;
  final FocusNode? focusNode;
  final bool autoFocus;
  final String? value;
  final Color? backgroundColor;
  final double height;
  final TextInputType? keyboardType;
  final bool showSearchIcon;
  final double searchIconSize;
  final TextStyle hintTextStyle;
  final TextStyle style;
  final TextEditingController? searchController;
  final int debounceTimeMilliseconds;
  final int sampleTimeInMilliseconds;

  final GestureTapCallback? onTap;

  const SearchBoxWidget({
    Key? key,
    required this.onValueChanged,
    this.onLastValueChanged,
    this.onClear,
    this.prefix,
    this.hintText = "请输入关键词",
    this.hintTextStyle = const TextStyle(
      color: const Color(0xffBFBFBF),
      fontSize: 14,
    ),
    this.style = const TextStyle(
      color: const Color(0xff252525),
      fontSize: 14,
    ),
    this.borderRadius = 28,
    this.horizontalMargin = 16,
    this.verticalMargin = 16,
    this.contentVerticalPadding = 6,
    this.leftPadding = 12,
    this.height = 40,
    this.onSubmitted,
    this.enabled = true,
    this.focusNode,
    this.autoFocus = false,
    this.value,
    this.backgroundColor,
    this.keyboardType,
    this.showSearchIcon = true,
    this.searchIconSize = 24,
    this.onTap,
    this.searchController,
    this.debounceTimeMilliseconds = 300,
    this.sampleTimeInMilliseconds = 3000,
  }) : super(key: key);

  @override
  SearchBoxWidgetState createState() => SearchBoxWidgetState();
}

class SearchBoxWidgetState extends State<SearchBoxWidget> {
  BehaviorSubject<String?> _searchSubject = BehaviorSubject<String?>();
  late TextEditingController _searchController;
  String? _currentKeyword;

  void _initSearchBox() {
    _currentKeyword = widget.value;
    _searchController =
        widget.searchController ?? TextEditingController(text: _currentKeyword);
    _searchSubject
        .debounceTime(Duration(milliseconds: widget.debounceTimeMilliseconds))
        .listen((value) {
      widget.onValueChanged(value);
    });

    if (widget.onLastValueChanged != null) {
      _searchSubject
          .sampleTime(Duration(milliseconds: widget.sampleTimeInMilliseconds))
          .listen((event) {
        widget.onLastValueChanged!(event);
      });
    }
  }

  void _disposeSearchBox() {
    try {
      _searchSubject.close();
    } catch (e) {
      debugPrint(e.toString());
    }
  }

  bool get hasKeyword => _currentKeyword?.isNotEmpty == true;

  @override
  void initState() {
    _initSearchBox();
    super.initState();
  }

  @override
  void dispose() {
    _disposeSearchBox();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (widget.enabled == false) {
      return GestureDetector(
        onTap: widget.onTap,
        child: _buildContent(),
      );
    } else {
      return _buildContent();
    }
  }

  Widget _buildContent() {
    _searchController
      ..text = _currentKeyword ?? ""
      ..selection = TextSelection.fromPosition(
          TextPosition(offset: _currentKeyword?.length ?? 0));
    return Card(
      color: widget.backgroundColor,
      elevation: 0,
      margin: EdgeInsets.symmetric(
          horizontal: widget.horizontalMargin, vertical: widget.verticalMargin),
      shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(widget.borderRadius)),
      child: SizedBox(
        height: widget.height,
        child: Stack(
          alignment: Alignment.centerLeft,
          children: <Widget>[
            TextField(
              focusNode: widget.focusNode,
              enabled: widget.enabled,
              style: widget.style,
              autofocus: widget.autoFocus,
              controller: _searchController,
              keyboardType: widget.keyboardType,
              decoration: InputDecoration(
                isDense: true,
                contentPadding: EdgeInsets.only(
                  top: widget.contentVerticalPadding,
                  bottom: widget.contentVerticalPadding,
                  left: widget.showSearchIcon ? 40 : widget.leftPadding,
                  right: 40,
                ),
                hintText: widget.hintText,
                hintStyle: widget.hintTextStyle,
                border: InputBorder.none,
                focusedBorder: InputBorder.none,
                enabledBorder: InputBorder.none,
              ),
              onChanged: _onSearchKeyWordChanged,
              onSubmitted: widget.onSubmitted,
              textInputAction: TextInputAction.search,
            ),
            if (widget.showSearchIcon)
              Padding(
                padding: const EdgeInsets.only(left: 15),
                child: Icon(
                  Icons.search,
                  color: Colors.grey,
                  size: widget.searchIconSize,
                ),
              ),
            ValueListenableBuilder(
              valueListenable: _searchController,
              builder: (context, value, child) => Visibility(
                visible: hasKeyword,
                child: Positioned(
                  right: 10,
                  child: GestureDetector(
                    child: Icon(Icons.clear, color: Colors.grey),
                    onTap: () {
                      widget.onClear?.call();
                      _onSearchKeyWordChanged(null);
                    },
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  void _onSearchKeyWordChanged(String? value) {
    if (value == null || value.isEmpty) {
      _searchController.clear();
    }
    _currentKeyword = value?.trim();
    //setState(() {});
    _searchSubject.add(_currentKeyword);
  }
}
